package com.example.hello.POJO;

import com.example.hello.HttpRequest;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;

public class POJO implements Comparable, Cloneable {

    protected String _id;
    protected String name;

    public LinkedHashMap<String, Object> toLinkedHashMap() {
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();

        List<Field> fields = Arrays.asList(getClass().getDeclaredFields());
        List<Method> methods = Arrays.asList(getClass().getDeclaredMethods());

        try {
            for (Field field : fields) {
                Method method = getMethodByName(methods, getterName(field.getName()));
                map.put(field.getName(), method.invoke(this));
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }

        return map;
    }

    public String get_id() {
        return _id;
    }

    public void set_id(String _id) {
        this._id = _id;
    }

    private String getterName(String string) {
        return "get" + string.substring(0, 1).toUpperCase() + string.substring(1);
    }

    private Method getMethodByName(List<Method> methods, String name) {
        for (Method method : methods)
            if (method.getName().equals(name)) return method;
        return null;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDecodedName() {
        try {
            return URLDecoder.decode(name, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return name;
        }
    }

    public String getEncodedName() {
        return name;
    }

    public String toJSON() {
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        String json = "";
        try {
            json = ow.writeValueAsString(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return json;
    }

    @Override
    public int compareTo(Object o) {
        return name.compareToIgnoreCase(((POJO) o).name);
    }

    /**
     * Use this method to create a resource if it doesn't already exist.
     */
    public static boolean create(String collection, POJO pojo) {
        return HttpRequest.executePost(collection, pojo.toJSON());
    }

    /**
     * Use this method to update a specific resource via the PUT request. Make sure
     * all fields are correctly changed before attempting to update the database entry.
     */
    public static boolean update(String collection, final POJO pojo) {
        POJO tmp = new POJO();
        try {
            tmp = (POJO) pojo.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        tmp.set_id(null);

        return HttpRequest.executePut(collection, tmp.toJSON());
    }
}